﻿using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Interactivity;

namespace OpenLightGroup.Common.Behaviors
{
    /// <summary>
    /// Allows the associated object to be moved to a different parent in the visual tree.
    /// </summary>
    [Description("Allows the associated object to be moved to a different parent in the visual tree.")]
    public class SwitchParentAction
        : TriggerAction<DependencyObject>
    {

        private DependencyObject _originalParent;

        /// <summary>
        /// FrameworkElement that will be moved between its original parent element and the NewParent object.
        /// </summary>
        public FrameworkElement Target
        {
            get { return (FrameworkElement)GetValue(TargetProperty); }
            set { SetValue(TargetProperty, value); }
        }

        /// <summary>
        /// DependencyProperty backing store for the Target property
        /// </summary>
        public static readonly DependencyProperty TargetProperty =
            DependencyProperty.Register("Target",
            typeof(FrameworkElement),
            typeof(SwitchParentAction),
            new PropertyMetadata(null));


        /// <summary>
        /// FrameworkElement that should be used as the secondary parent of the target element.
        /// </summary>
        public DependencyObject NewParent
        {
            get { return (DependencyObject)GetValue(NewParentProperty); }
            set { SetValue(NewParentProperty, value); }
        }

        /// <summary>
        /// DependencyProperty backing store for the NewParent property
        /// </summary>
        public static readonly DependencyProperty NewParentProperty =
            DependencyProperty.Register("NewParent",
            typeof(DependencyObject),
            typeof(SwitchParentAction),
            new PropertyMetadata(null));


        /// <summary>
        /// Called when the action is triggered.
        /// </summary>
        /// <param name="parameter">Not used.</param>
        protected override void Invoke(object parameter)
        {
            this.SwapParent();
        }

        /// <summary>
        /// Handles the logic to determine which parent to move the target to.
        /// </summary>
        private void SwapParent()
        {
            if (this._originalParent == null)
                this._originalParent = this.Target.Parent;


            DependencyObject newParent;

            if (this.Target.Parent == this._originalParent)
            {
                newParent = this.NewParent;
            }
            else
            {
                newParent = this._originalParent;
            }

            this.RemoveTarget();
            this.AddTarget(newParent);

        }

        /// <summary>
        /// Adds the target to a new parent.
        /// </summary>
        /// <param name="newParent">The object to move the Target to.</param>
        protected void AddTarget(DependencyObject newParent)
        {
            if (newParent != null)
            {
               
                if (typeof(Border).IsAssignableFrom(newParent.GetType()))
                    ((Border)newParent).Child = this.Target;

                else if (typeof(Panel).IsAssignableFrom(newParent.GetType()))
                    ((Panel)newParent).Children.Add(this.Target);

                else if (typeof(ContentControl).IsAssignableFrom(newParent.GetType()))
                    ((ContentControl)newParent).Content = this.Target;


            }
        }

        /// <summary>
        /// Removes the Target from its current parent.
        /// </summary>
        protected void RemoveTarget()
        {

            if (typeof(Border).IsAssignableFrom(this.Target.Parent.GetType()))
                ((Border)this.Target.Parent).Child = null;

            else if (typeof(Panel).IsAssignableFrom(this.Target.Parent.GetType()))
                ((Panel)this.Target.Parent).Children.Remove(this.Target);

            else if (typeof(ContentControl).IsAssignableFrom(this.Target.Parent.GetType()))
                ((ContentControl)this.Target.Parent).Content = null;

        }

    }
}
